package pool

import (
	"io"
	"log"
	"sync"
	"errors"
)

type Pool struct {
	closed bool
	factory func()(io.Closer, error)
	Resources chan io.Closer
	m sync.Mutex
}

var ErrPoolClosed = errors.New("Pool has been closed!")

func New(fn func()(io.Closer, error), size uint)*Pool{
	if size<=0{
		log.Println("Tool small size!")
		return nil
	}
	return &Pool{
		factory: fn,
		Resources: make(chan io.Closer, size),
	}
}

// the return of Acquire must be the same as Pool.factory
// because this function returns the result of the call of the Pool.factory
func (p *Pool)Acquire() (io.Closer, error){
	select {
	//todo if it will happen that it get resource successfully while error is not nil
	case r,ok := <- p.Resources:
		log.Println("Acquire Success, shared resource")
		if !ok{
			return nil, ErrPoolClosed
		}
		return r,nil
	default:
		log.Println("Acquire Fail, generate new resource")
		return p.factory()
	}
}
func (p *Pool)Release(r io.Closer){
	p.m.Lock()
	defer p.m.Unlock()

	if p.closed{
		r.Close()
		return
	}
	select {
	//向一个满的缓冲channel中放入数据会阻塞，但在select中例外
	case p.Resources <- r:
		log.Println("release resource [channel]")
	default:
		log.Println("release resource [closed]")
		r.Close()
	}
}
//page 178
func (p *Pool)Close(){
	p.m.Lock()
	defer p.m.Unlock()
	if p.closed{
		return
	}
	p.closed = true
	//清空资源前先将通道关闭
	//因为接下来要将通道中缓存的资源释放掉
	//都释放完毕后则变成一个空的缓存通道
	//从一个空的缓存通道获取数据会阻塞
	close(p.Resources)

	for r:=range p.Resources {
		r.Close()
	}
}